/**
 * @auther jiagnqifan
 * @since 2016-03-31
 */

var Models = require('../../../../models');
var ProductConfig = Models.ProductConfig;
var Product = Models.Product;
var Cert = Models.Cert;
var Project = Models.Project;

var logger = require('log4js').getLogger();
var EventProxy = require('eventproxy');
var tools = require('../../../../common/tools.js');
var zip = require('../../../../common/zip.js');
var fs = require('fs');
var path = require('path');
var request = require('request');
var config = require('../../../../config.json');
var url = require('url');
var _ = require("lodash");
var builder_url = url.format(config.app.builder);
var spaces_url = builder_url + '/spaces';
var product_repo = config.product_repo;
var ProjectProxy = require('../../../../proxy/project.js');
var pre_url = config.store.store_private;
var downloadGoods = require('../../local_repositories.js').downloadGoods;
var LocalRepoProxy = require('../../../../proxy/local_repo.js');
var local_repo_path = config.local_repo_addr;
var sdp_agent = config.server_agent.host + ":" + config.server_agent.port;
//TODO
/*
 1. 证书配置文件生成

 */



//util methods

function tryCallback(callback, err, data) {
    if (err) {
        logger.error(err);
    }
    if ('function' == typeof callback) {
        callback(err, data);
    }
}


function setBuildState(build, state, callback) {   //执行该方法时    messageBroker.emit('build_state_update',...)
    logger.info('change state of ' + build._id + ' to ' + state);
    build.state = state;
    build.save(callback);
}

//=============================================================


/**
 1. 获取token
 2. 上传文件
 2. 发起构建
 *
 */
function start(build, callback) {

    var ep = new EventProxy();

    //err handle
    ep.fail(function (message) {
        setBuildState(build, 'error');
        tryCallback(callback, message);
    });

    //set state to readying, then to start
    setBuildState(build, 'readying', function (err, data) {
        if (err) {
            return ep.throw('error occurs when change build state to readying.');
        }
        //messageBroker.emit('build_state_update',...)
        ep.emit('state_change_to_readying');
    });

    //do ready after state change to readying
    ep.on('state_change_to_readying', function ready() {

        logger.info('state_change_to_readying');

        //find project dir from product config

        var product_config_ids = build.config.product_configs;
        if (!product_config_ids || !product_config_ids.length) {
            var message = 'cannot start build because no product config.';
            return tryCallback(callback, message);
        }
        //移动构建目前支持一次构建一个产品, 没想好如果发起多次构建的话进度如何显示
        var product_config_id = product_config_ids[0];

        ProductConfig.findById(product_config_id, function (err, product_config) {

            if (err || !product_config) {
                return ep.throw('cannot find product_config:' + product_config_id);
            }

            logger.info('product config:' + product_config_id + ' found.');

            var projects = product_config.projects;

            if (!projects || !projects.length) {
                var message = 'cannot start build because no product config.';
                return ep.throw(message);
            }
            //
            //var temp_dir = null;
            //try {
            //    temp_dir = tools.createTempDirSync();
            //} catch (e) {
            //    return ep.throw('创建临时目录失败' + (e.message ? e.message : e));
            //}

            //use this for token of build
            var spaceID = null;
            var RN_plugins = [];
            var project_location = "";

            var cert_info = {};
            var project_info = {};
            var cert_id = product_config.detail.certificate;

            ep.on("get_cert_info", function () {
                Project.findById(product_config.project, function (err, data) {
                    if (err) {
                        return tryCallback(callback, 'get project with project_id: ' + product_config.project + ' faild.');
                    }
                    project_info = data;
                    request({
                        url: sdp_agent + '/appAndroidBuild',
                        method: "POST",
                        json: true,
                        body: {
                            project_info: project_info,
                            cert_info: cert_info,
                            projects: projects
                        }
                    }, function (err, response, data) {
                        if (err) {
                            return tryCallback(callback, 'get project with project_id: ' + product_config.project + ' faild.');
                        }
                        ep.emit("ready_completed");

                    })

                });
            })

            if (cert_id == "default" || typeof(cert_id) == "undefined") {
                cert_info = null;
                ep.emit('get_cert_info');
            } else {
                Cert.findById(cert_id, function (err, data) {
                    if (err) {
                        return ep.throw(err);
                    }
                    cert_info = data;
                    ep.emit('get_cert_info');
                });
            }
        });



    });


    ep.on('ready_completed', function (spaceID) {

        logger.info('ready_completed');

        build.token = spaceID;
        build.save(function (err, data) {
            if (err) {
                return ep.throw('error occurs when set token of build [' + build._id + '] to[' + spaceID + '].');
            }
            setBuildState(build, 'building', ep.done('state_change_to_building'));
        });

    })

    ep.on('state_change_to_building', function () {
        //messageBroker.emit('build_state_update',...)
        logger.info('state_change_to_building');

        tryCallback(callback, null, build);
    })


    //make temp  workspace
    //zip project

    //prepare .json file
    //zip file

}

function tryComplete(build, callback) {
    getIsComplete(build, function (err, completed) {
        if (err) {
            logger.error(err);
            if ('function' === typeof callback) {
                callback(err);
            }
            return;
        }
        logger.info(build._id + ' completed:' + completed);

        if (completed) {
            complete(build, callback);
        }
    })

}
//check is comlete form builder server
function getIsComplete(build, callback) {
    getProgressInfo(build, function (err, info) {
        if (err) {
            logger.error(err);
            callback(err);
        } else if (info) {
            logger.info(info);
            var state = info.state;
            callback(null, 2 == state || state < 0);
        }
    });
}

function getProgressInfo(build, callback) {
    var url = builder_url + '/query/spaces/' + build.token;
    request(url, function (err, response, body) {
        logger.info(body);
        logger.info(err);
        logger.info(response.statusCode);
        if (!err && response.statusCode == 200) {
            logger.info('true');
            logger.info(JSON.parse(body));
            callback(null, JSON.parse(body));
        } else {
            logger.info('false');
            callback(err ? err : 'statusCode:' + response.statusCode);
        }
    });
}

//get hundred percent of progress, return integer
function getProgress(build, callback) {
    callback(null, 0);
}

function cancel(build, callback) {

}
function cancelable(build, callback) {
    callback(null, false);
}

//do something after complete
/**
 * 1.下载文件
 *
 */
function complete(build, callback) {

    var ep = new EventProxy();

    //prepare. set err handler
    ep.fail(function (err) {
        logger.err(err);
        callback(err);
    });


    //step1. change state to completing
    ep.on('begin', function () {
        logger.info('set state to completing.[' + build._id + ']');
        build.state = 'completing';
        build.save(function (err, data) {
            if (err) {
                return ep.throw(err);
            }
            build = data;
            //messageBroker.emit('build_state_update',...)
            ep.emit('state_change_to_completing');
        });

    });

    //step2. check result
    ep.on('state_change_to_completing', function () {
        getProgressInfo(build, function (err, info) {
            if (2 == info.state) {
                logger.info('set result to success.[' + build._id + ']');
                build.result = 'success';
                build.save(function (err, data) {
                    if (err) {
                        return ep.throw(err);
                    }
                    ep.emit('result_is_success');
                });
            } else {
                logger.info('set result to failed.[' + build._id + ']');
                build.result = 'failed'
                build.save(function (err, data) {
                    if (err) {
                        return ep.throw(err);
                    }
                    //messageBroker.emit('build_state_update',...)
                    ep.emit('completed');
                });
            }
        });
    });

    //step3. find product config
    ep.on('result_is_success', function () {
        getProgressInfo(build, function (err, info) {
            if (info.state < 0) {
                build.result = 'failed'
                build.save(function (err, data) {
                    if (err) {
                        return ep.throw(err);
                    }
                    //messageBroker.emit('build_state_update',...)
                    ep.emit('completed');
                });
            } else {
                logger.info('set result to failed.[' + build._id + ']');
                var product_config_id = build.config.product_configs[0];
                ProductConfig.findById(product_config_id, function (err, product_config) {
                    if (err || !product_config) {
                        return ep.throw('can not find product config:' + product_config_id);
                    } else {
                        ep.emit('product_config_found', product_config);
                    }
                });
            }
        });

    })


    //step4. download file
    ep.on('product_config_found', function (product_config) {
        logger.info('product_config_found');
        var url = builder_url + '/spaces/' + build.token + '/nectar.zip';
        try {
            fs.accessSync(product_repo, fs.R_OK);
        } catch (e) {
            fs.mkdirSync(product_repo);
        }
        var dir = path.join(product_repo, build._id.toString());
        tools.ensureDirSync(dir);
        var file_path = path.join(dir, 'nectar.zip');
        tools.download(url, file_path, function (err) {
            if (err) {
                return ep.throw(err);
            }
            ep.emit('file_downloaded', file_path, product_config);
        });
    });


    //step5. add product info to db
    ep.on('', function (file_path, product_config) {
        logger.info('file_downloaded');
        var product = new Product();
        product.config = product_config._id;
        product.version = product_config.version;
        product.url = 'file:' + file_path;
        product.save(function (err, data) {
            if (err) {
                return ep.throw(err);
            }
            ep.emit('product_created');
        });
    })

    //step6. change build state to completed
    ep.on('product_created', function () {
        logger.info('product_created');
        build.state = 'completed';
        build.save(function (err, data) {
            if (err) {
                return ep.throw(err);
            }
            //messageBroker.emit('build_state_update',...)
            ep.emit('completed', data._id);
        });
    });

    //step7. callback
    ep.on('completed', function (product_id) {
        logger.info('completed. build_id:' + build._id + ", product_id: " + product_id);
        tryCallback(callback, null, product_id);
    });

    ep.emit('begin');
}

function getAllProjects(project_id, callback) {
    var platform = require('os').platform();
    var isWin = false;
    switch (platform) {
        case 'linux' :
        case 'darwin' :
            break;
        case 'win32' :
            isWin = true;
            break;
    }
    var epx = new EventProxy();
    var project = {};
    epx.fail(function (err) {
        callback(err);

    });
    var init_target_for_master_wkp = require('../../workspace/workspace.js').init_target_for_master_wkp;
    epx.on("get_project_info", function (project) {
        init_target_for_master_wkp(project, isWin, function (err) {
            if (err) {
                logger.error("init target for master wkp " + project.name + " error");
                logger.error(err);
                callback(err);
            } else {
                epx.emit("create_link_target");
            }
        });
    });
    epx.on("create_link_target", function () {
        var project_name = project.name;
        var namespace = project.namespace;
        var master_repo_path = path.join(config.master_workspaces, namespace, project_name, "source", project_name);
        var pullGit = require('../../workspace/gitoper.js').pullGit;
        var simpleGit = require('simple-git')(master_repo_path);
        pullGit(master_repo_path, "origin", "develop", function (error) {
            if (error) {
                logger.error("合并分支失败");
                logger.error(error);
                callback("merge develop error")
            } else {
                pullGit(master_repo_path, config.workspace.gitolite.repo_pre + namespace + '/' + project_name, 'master', function (err, data) {
                    if (err) {
                        logger.error("pull master error");
                        callback("pull master error")
                    } else {
                        logger.info("projects ready");
                        callback(null, "projects ready");
                    }
                });
            }
        });
    });

    ProjectProxy.getProjectById(project_id, function (err, project_info) {
        if (err) {
            logger.error("get project project_id error:");
            logger.error(err);
            return callback(err);
        }
        project = project_info;
        //create_wkp_dirs(project);
        epx.emit("get_project_info", project);
    });

}

//Build Type Interfaces
exports.start = start;
exports.cancel = cancel;
exports.getProgress = getProgress;
exports.tryComplete = tryComplete;
exports.cancelable = cancelable;
exports.getAllProjects = getAllProjects;
